home *** CD-ROM | disk | FTP | other *** search
- ;==========================================================================;
- ; 8250 Extended functions ;
- ; ;
- ; Copyright 1983 by William E. Westfield. All rights reserved. ;
- ; Copyright 1986, 1988, 1991 by H. Roy Engehausen. All rights reserved. ;
- ; This software may be freely distributed and used, but it may not ;
- ; under any circumstances be sold by anyone other than the author. ;
- ; It may be distributed by a commercial company as long as it is ;
- ; for no cost. ;
- ; ;
- ; AH = 4 Inquiry ;
- ; ------------------ ;
- ; AH returns 0AAH. AL returns 055H. This call is used to see if this ;
- ; driver has been loaded for a particular port. ;
- ; ;
- ; AH = 5 Drop RTS ;
- ; ------------------- ;
- ; This drops DTR (pin 20) and RTS (pin 4). Used to tell the TNC not to ;
- ; send any more information. TNC-1 and PK-232 use pin 4 for handshaking. ;
- ; TNC-2 uses pin 20 (dont ask me why!) No return value. ;
- ; ;
- ; AH = 6 Raise RTS ;
- ; -------------------- ;
- ; Raise DTR and RTS. No return value. ;
- ; ;
- ; AH = 7 Send Break ;
- ; --------------------- ;
- ; Generates a "Break". No return value. ;
- ; ;
- ; AH = 8 Non-destructive Read ;
- ; ------------------------------- ;
- ; Returns the next character in the buffer in AL without removing it from ;
- ; the buffer. AH value same as code 1. No check for character ready ;
- ; ;
- ; AH = 9 Set/Get options ;
- ; -------------------------- ;
- ; Set the current option byte to AL returning the old option byte in AL. ;
- ; ;
- ; AH = A Write buffer ;
- ; ----------------------- ;
- ; Sends CX characters starting at DI:ES ;
- ; ;
- ; AH = B Read buffer ;
- ; ---------------------- ;
- ; Receives up to CX characters starting at DI:ES. CX set to actual ;
- ; count read ;
- ; ;
- ; AH = C Send/Receive DED Hostmode buffer ;
- ; ------------------------------------------- ;
- ; Not implemented for 8250 ;
- ; ;
- ;==========================================================================;
-
- ;==========================================================================;
- ; Inquiry ;
- ;==========================================================================;
-
- rsint_8250_inquiry:
-
- MOV AX,0AA55H ; Set footprint
- JMP rsint_exit ; All done
-
- ;==========================================================================;
- ; Drop RTS/DTR handshaking ;
- ;==========================================================================;
-
- rsint_8250_droprts:
-
- MOV DX,baseaddr[SI] ; Get base address for chip
- ADD DX,mcr_8250 ; Select MCR
- MOV AL,hoff_8250 ; Turn off sending from distant end
- OUT DX,AL ;
-
- OR flags[SI],flags_useoff ; Signal user wants handshake off
-
- JMP rsint_exit ; All done
-
- ;==========================================================================;
- ; Turn on RTS/DTR handshaking ;
- ;==========================================================================;
-
- rsint_8250_raiserts:
-
- MOV DX,baseaddr[SI] ; Get base address for chip
- ADD DX,mcr_8250 ;
- MOV AL,hon_8250 ; Raise DTR, RTS, and OUT2. OUT2 turns
- OUT DX,AL ; on interrupts.
-
- AND flags[SI],0FFH-flags_useoff ; Turn off force handshake flag
-
- JMP rsint_exit ; All done
-
- ;==========================================================================;
- ; Break! ;
- ;==========================================================================;
-
- rsint_8250_sendbrk:
-
- ;--------------------------------------------------------------------------;
- ; First we see if we are going to use a hardware break or a ;
- ; simulated break using three control "C" ;
- ;--------------------------------------------------------------------------;
-
- TEST options[SI],opt_brktr ; Translate break to control "C"
- JNZ rsint_8250_sendbrk_tr ; Yep!
-
- ;--------------------------------------------------------------------------;
- ; Hardware break. Set the bit in the LCR (without disturbing the rest ;
- ; and then loop for a while ;
- ;--------------------------------------------------------------------------;
-
- PUSH ES ; We are going to use ES, so save it
- MOV AX,040H ; Point ES down to the BIOS region
- MOV ES,AX
-
- MOV DX,baseaddr[SI] ; Get base address for chip
- ADD DX,lcr_8250 ; Select LCR
- IN AL,DX ; Read LCR
- PUSH AX ; and save it
-
- OR AL,lcr_8250_sb ; Force on the SET BREAK bit
- OUT DX,AL ; and output the SET BREAK bit
-
- rsint_8250_sendbrk_too_big:
-
- MOV CX, WORD PTR ES:[006Ch] ; Get current time tick count
- MOV BX,CX ; Save it in bx
- ADD CX,4 ; Calc target end-of-loop tick count
-
- CMP CX, BX ; Will it roll over?
- JB rsint_8250_sendbrk_lp2 ; Yep...
-
- ; CX > BX. No rollover needed
- ; If tick is not between bx and cx, then exit loop
-
- rsint_8250_sendbrk_lp1:
-
- MOV AX,WORD PTR es:[006Ch] ; Get time tick
-
- CMP AX,CX ; Has tick past target?
- JA rsint_8250_sendbrk_done ; Yep, done
-
- CMP AX,BX ; Has tick rolled over?
- JB rsint_8250_sendbrk_done ; Yep, done
-
- JMP rsint_8250_sendbrk_lp1 ; Need to loop
-
- ; CX < BX -- We will roll over
- ; If tick is not outside BX and CX, then exit loop
-
- rsint_8250_sendbrk_lp2:
-
- MOV AX,WORD PTR es:[006Ch] ; Get time tick
-
- CMP AX,CX ; Has tick past target?
- JB rsint_8250_sendbrk_lp2 ; Nope, loop
-
- CMP AX,BX ; Has tick past target?
- JAE rsint_8250_sendbrk_lp2 ; Nope, loop
-
- ; Break is complete
-
- rsint_8250_sendbrk_done:
-
- POP AX ; Retrieve the lcr status
- OUT DX,AL ; and output it
-
- POP ES ; Retrieve ES
-
- JMP rsint_exit ; All done
-
- ;--------------------------------------------------------------------------;
- ; Translated break. Send three control-C in a row ;
- ;--------------------------------------------------------------------------;
-
- rsint_8250_sendbrk_tr:
-
- MOV BX,baseaddr[SI] ; Get base address for chip
- MOV CX,3 ; Three characters wanted
- MOV AH,03H ; Control-C
-
- ;--------------------------------------------------------------------------;
- ; Loop thru here 3 times ;
- ;--------------------------------------------------------------------------;
-
- rsint_8250_sendbrk_loop1: ;
-
- ;--------------------------------------------------------------------------;
- ; Loop waiting for TBE ;
- ;--------------------------------------------------------------------------;
-
- MOV DX,BX ; Compute port address for the LSR
- ADD DX,lsr_8250 ;
-
- rsint_8250_sendbrk_loop2: ; Loop here until we can send
-
- IN AL,DX ; Get the LSR into AX
- TEST AL,lsr_8250_thre ; THR empty?
- JZ rsint_8250_sendbrk_loop2 ; No.. Loop back
-
- ;--------------------------------------------------------------------------;
- ; Out the character ;
- ;--------------------------------------------------------------------------;
-
- MOV AL,AH ; Get ready to out character
-
- MOV DX,BX ; Compute port address for the THR
- ADD DX,thr_8250 ; and then
- OUT DX,AL ; out the character
-
- ;--------------------------------------------------------------------------;
- ; Loop through all three characters ;
- ;--------------------------------------------------------------------------;
-
- LOOP rsint_8250_sendbrk_loop1 ; If not done then loop back
-
- JMP rsint_exit ; All done
-
- ;==========================================================================;
- ; Non destructive read ;
- ;==========================================================================;
-
- rsint_8250_ndr:
-
- ;--------------------------------------------------------------------------;
- ; Get the current character in the buffer. Make no check for character ;
- ; ready ;
- ;--------------------------------------------------------------------------;
-
- MOV BX,buffer_r_out[SI] ; Get buffer output pointer
- MOV ES,buffer_r_a[SI] ; Get buffer segment
- MOV AL,ES:[BX] ; Get character from buffer..
-
- ;--------------------------------------------------------------------------;
- ; Set the status byte. ;
- ;--------------------------------------------------------------------------;
-
- MOV AH,last_rs[SI] ; Get last LSR from receive
- AND AH,0FFH-lsr_8250_dr ; Remove data ready bit
- CMP BX,buffer_r_in[SI] ; Anything left in buffer?
- JE rsint_8250_ndr_go ; Nope so leave
- OR AH,lsr_8250_dr ; Turn on data ready
-
- rsint_8250_ndr_go: ;
-
- JMP rsint_exit ; All done
-
- ;==========================================================================;
- ; Set option byte ;
- ;==========================================================================;
-
- rsint_8250_sopt: ;
-
- XCHG AL,options[SI] ;
-
- JMP rsint_exit ; All done
-
- ;==========================================================================;
- ; Block write ;
- ;==========================================================================;
-
- rsint_8250_buffw: ;
-
- TEST options[SI],opt_trbuf ; Transmit buffering turned on?
- JNZ rsint_8250_bufw_bw ; Yes.. go there now!
-
- ;--------------------------------------------------------------------------;
- ; Unbuffered block write ;
- ;--------------------------------------------------------------------------;
-
- ;--------------------------------------------------------------------------;
- ; Get the user's parameters and initialize ;
- ;--------------------------------------------------------------------------;
-
- MOV BX,SP ; Need access to stack
- MOV DI,SS:stack_di[BX] ; Get the offset
- MOV ES,SS:stack_es[BX] ; Get the displacement
- MOV BX,SS:stack_cx[BX] ; Get the size to send
- MOV CX,baseaddr[SI] ; Get base address for chip
-
- ;--------------------------------------------------------------------------;
- ; Loop sending ;
- ;--------------------------------------------------------------------------;
-
- rsint_8250_bufw_ubw:
-
- MOV AH,ES:[DI] ; Get character to send
- CALL rsint_8250_send_unb ; Send it
-
- INC DI ; Bump pointer
- DEC BX ; -1 from count
- JNZ rsint_8250_bufw_ubw ; Loop back
-
- ;--------------------------------------------------------------------------;
- ; Store results and exit ;
- ;--------------------------------------------------------------------------;
-
- SUB AX,AX ; Need a zero
- MOV BX,SP ; Need access to stack
- MOV SS:stack_di[BX],DI ; Set the offset
- MOV SS:stack_cx[BX],AX ; Set the count remaining(0)
-
- JMP rsint_8250_status ; Do a status
-
- ;--------------------------------------------------------------------------;
- ; Buffered block write ;
- ;--------------------------------------------------------------------------;
-
- rsint_8250_bufw_bw: ;
-
- ;--------------------------------------------------------------------------;
- ; Get the user's parameters and initialize ;
- ;--------------------------------------------------------------------------;
-
- MOV BX,SP ; Need access to stack
- MOV DX,SS:stack_cx[BX] ; Get the size to move
- MOV DI,buffer_t_in[SI] ; Get buffer input pointer
-
- AND flags[SI],0FFH-flags_was_e ; Turn off buffer empty flag
-
- OR DX,DX ; Anything to send?
- JNZ rsint_8250_bufw_loop; Yep
-
- CALL rsint_8250_bufw_int ; Cause a hardware interrupt
- JMP rsint_8250_bufw_end ; Nope
-
- ;--------------------------------------------------------------------------;
- ; This is the loop to move data to the buffer ;
- ; DI = input buffer position. ;
- ; DX = count left to move ;
- ;--------------------------------------------------------------------------;
-
- rsint_8250_bufw_loop: ; Move to buffer loop
-
- ;--------------------------------------------------------------------------;
- ; See if the buffer has gone empty and remember that. If it has then ;
- ; we will need to kick the interrupt servicer ;
- ;--------------------------------------------------------------------------;
-
- MOV AX,buffer_t_out[SI] ; See where the out pointer is
- ; CMP AX,DI ; Are they the same (empty buffer)
- ; JNE rsint_8250_bufw_ne ; No.... Buffer has something in it
- ; OR flags[SI],flags_was_e ; Yes... Turn on buffer empty flag
- rsint_8250_bufw_ne:
-
- ;--------------------------------------------------------------------------;
- ; Now get the space left in the buffer. ;
- ;--------------------------------------------------------------------------;
-
- CMP AX,DI ; Is the buffer wrapped?
- JG rsint_8250_bufw_nw ; Not wrapped
- MOV CX,AX ; Save AX
- MOV AX,buffer_size+1 ; Locate buffer_end + 1 for now
- JCXZ rsint_8250_bufw_nw ; Was AX zero?
- DEC AX ;
- rsint_8250_bufw_nw:
-
- SUB AX,DI ; AX = space left in buffer
- JNZ rsint_8250_bufw_ok ; Space is left!
- JMP rsint_8250_bufw_end ; No space left.. Its over
- rsint_8250_bufw_ok:
-
- ;--------------------------------------------------------------------------;
- ; Now calculate the size to move in this iteration. ;
- ; It will be the smallest of: ;
- ; 1) Buffer space (now in AX) ;
- ; 2) Data size (now in DX) ;
- ;--------------------------------------------------------------------------;
-
- CMP AX,DX ;
- JLE rsint_8250_bufw_m1 ;
- MOV AX,DX ;
- rsint_8250_bufw_m1: ;
-
- ; CMP AX,31 ; 63 bytes per move
- ; JLE rsint_8250_bufw_m2 ;
- ; MOV AX,31 ; Move only 63
- rsint_8250_bufw_m2: ;
-
-
- ;--------------------------------------------------------------------------;
- ; Update the counters ;
- ;--------------------------------------------------------------------------;
-
- SUB DX,AX ; Drop the count to be moved by this move.
-
- ;--------------------------------------------------------------------------;
- ; Prep all the registers and do the move ;
- ;--------------------------------------------------------------------------;
-
- ASSUME DS:NOTHING;
-
- MOV CX,AX ; Get count
- MOV AX,SI ; Save SI
- MOV ES,buffer_t_a[SI] ; Get buffer segment
- MOV DS,SS:stack_es[BX] ; Get input segment
- MOV SI,SS:stack_di[BX] ; Get input offset
- ; CLI
- CLD ; The counter should go up!
- REP MOVSB ; Do the move
- MOV SS:stack_di[BX],SI ; Put back updated offset.
- MOV SI,AX ; Restore SI
- MOV CX,CS ; Restore DS
- MOV DS,CX ;
- ; STI
-
- ASSUME DS: everything ;
-
- ;--------------------------------------------------------------------------;
- ; Update the counters ;
- ;--------------------------------------------------------------------------;
-
- CMP DI,buffer_size ; Wrap the input pointer around the
- JL rsint_8250_bufw_now ; buffer if necessary
- SUB DI,DI ;
- rsint_8250_bufw_now: ;
-
- ;--------------------------------------------------------------------------;
- ; See if the buffer is empty disregarding what we just put int it. ;
- ; we will need to kick the interrupt servicer ;
- ;--------------------------------------------------------------------------;
-
- MOV AX,buffer_t_in[SI] ; See where the "old" input pointer is
- MOV buffer_t_in[SI],DI ; Save "new" input pointer
- CMP AX,buffer_t_out[SI] ; See where the out pointer is
- JNE rsint_8250_bufw_noi ; Not the same. Buffer still ok
- ; TEST flags[SI],flags_was_e ; Was it empty
- ; JZ rsint_8250_bufw_noi ; Not the same. Buffer still ok
-
- ;--------------------------------------------------------------------------;
- ; If buffer was empty, cause a false hardware interrupt by setting the IIR ;
- ; to zero and then back. This will cause an THR empty interrupt. ;
- ;--------------------------------------------------------------------------;
-
- CALL rsint_8250_bufw_int
-
- rsint_8250_bufw_noi: ;
-
- ;--------------------------------------------------------------------------;
- ; Finish up and get ready to loop again ;
- ;--------------------------------------------------------------------------;
-
- OR DX,DX ; Anything more to send?
- JZ rsint_8250_bufw_end ; Nope
-
- JMP rsint_8250_bufw_loop; Go loop
-
- ;--------------------------------------------------------------------------;
- ; Here is where we end ;
- ;--------------------------------------------------------------------------;
-
- rsint_8250_bufw_end: ;
- MOV buffer_t_in[SI],DI ; Save input pointer
- MOV SS:stack_cx[BX],DX ; Bytes remaining
-
- JMP rsint_8250_status ; Do a status
-
- ;==========================================================================;
- ; Case a false hardware interrupt on the chip. ;
- ;==========================================================================;
-
- ;--------------------------------------------------------------------------;
- ; If buffer was empty, cause a false hardware interrupt by setting the IIR ;
- ; to zero and then back. This will cause an THR empty interrupt. ;
- ;--------------------------------------------------------------------------;
-
- rsint_8250_bufw_int:
-
- ; MOV AL,hiv[SI] ; Get the hardware interrupt vector address
- ; MOV rsint_8250_bufw_int,AL ; Put it where we need it
- ; JMP $+2 ; Flush interrupt buffer
- ; INT 00H ; Interrupt!
- ; ORG $-1
- ;sint_8250_bufw_int DB ? ; Place to put interrupt number
- ;
-
- CLI ; No interrupt please!
-
- MOV CX,DX ; Save DX
-
- MOV DX,baseaddr[SI] ; Get base address for chip
- ADD DX,ier_8250 ; Address IER
- IN AL,DX ; Get it
- MOV AH,AL ; Save it
- SUB AL,AL ; Now send zero
- OUT DX,AL ; to IER
- MOV AL,AH ; Now restore IER
- JMP $+2 ; Delay
- OUT DX,AL ;
- JMP $+2 ; Delay
- STI ; Enable
-
- MOV DX,CX ; Restore DX
-
- RET
-
- ;==========================================================================;
- ; Block read ;
- ;==========================================================================;
-
- rsint_8250_buffr: ;
-
- ;--------------------------------------------------------------------------;
- ; Initialize ;
- ;--------------------------------------------------------------------------;
-
- MOV BX,SP ; Need pointer for stack
- SUB DX,DX ; Number of bytes moved.
-
- ;--------------------------------------------------------------------------;
- ; This is the main move loop ;
- ; DX = total_bytes moved ;
- ;--------------------------------------------------------------------------;
-
- rsint_8250_bufr_loop:
-
- ;--------------------------------------------------------------------------;
- ; If no data left then we can leave ;
- ;--------------------------------------------------------------------------;
-
- MOV DI,buffer_r_out[SI] ; Get buffer output pointer
- MOV AX,buffer_r_in[SI] ; Get buffer input pointer
- CMP AX,DI ; See in anything in buffer
- JE rsint_8250_bufr_done ; Nope.. Quit
-
- ;--------------------------------------------------------------------------;
- ; Now get the data left in the buffer. ;
- ;--------------------------------------------------------------------------;
-
- MOV CX,AX ; CX = end of area to move
- CMP AX,DI ; Is the buffer wrapped?
- JGE rsint_8250_bufr_nw ; Not wrapped
- MOV CX,buffer_size ; Wrapped. Locate end for now
- rsint_8250_bufr_nw:
-
- SUB CX,DI ; CX = data left in buffer
-
- MOV AX,SS:stack_cx[BX] ; Get user's buffer size
- OR AX,AX ; Any space left?
- JZ rsint_8250_bufr_done ; Nope.. Quit
-
- ;--------------------------------------------------------------------------;
- ; Now calculate the size to move in this iteration. ;
- ; It will be the smallest of: ;
- ; 1) Data size (now in CX) ;
- ; 2) User's buffer size ;
- ;--------------------------------------------------------------------------;
-
- CMP CX,AX ;
- JLE rsint_8250_bufr_m1 ;
- MOV CX,AX ;
- rsint_8250_bufr_m1: ;
-
- ;--------------------------------------------------------------------------;
- ; Update counters now ;
- ;--------------------------------------------------------------------------;
-
- ADD DX,CX ; Bump bytes moved counter
- SUB AX,CX ; Show buffer usage
- MOV SS:stack_cx[BX],AX ; And store back
-
- ;--------------------------------------------------------------------------;
- ; Prep all the registers and do the move ;
- ;--------------------------------------------------------------------------;
-
- ASSUME DS:NOTHING;
-
- MOV AX,SI ; Save SI
- MOV DS,buffer_r_a[SI] ; Get buffer segment
- MOV SI,DI ; Set buffer offset
- MOV ES,SS:stack_es[BX] ; Get input segment
- MOV DI,SS:stack_di[BX] ; Get input offset
- CLD ; The counter should go up!
- REP MOVSB ; Do the move
- MOV SS:stack_di[BX],DI ; Put back updated offset.
- MOV DI,SI ; Restore an updated DI
- MOV SI,AX ; Restore SI
- MOV AX,CS ; Restore DS
- MOV DS,AX ;
-
- ASSUME DS: everything ;
-
- ;--------------------------------------------------------------------------;
- ; Update things ;
- ;--------------------------------------------------------------------------;
-
- CMP DI,buffer_size ; Wrap the input pointer around the
- JL rsint_8250_bufr_now ; buffer if necessary
- SUB DI,DI ;
- rsint_8250_bufr_now: ;
- MOV buffer_r_out[SI],DI ; Set buffer output pointer
-
- ;--------------------------------------------------------------------------;
- ; Loop back ;
- ;--------------------------------------------------------------------------;
-
- JMP rsint_8250_bufr_loop ;
-
- ;--------------------------------------------------------------------------;
- ; Here is where we end ;
- ;--------------------------------------------------------------------------;
-
- rsint_8250_bufr_done : ;
-
- MOV BX,SP ; Use SP in BX
- MOV SS:stack_cx[BX],DX ; Bytes moved
-
- JMP rsint_8250_status ; Do a status
-
- ;==========================================================================;
- ; WA8DED Mode ;
- ;==========================================================================;
-
- rsint_8250_ded: ;
-
- JMP rsint_exit ; All done